package hexagon.security.core.domain;

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import org.apache.commons.lang3.Validate;

import javax.persistence.Entity;
import javax.persistence.Table;
import java.util.LinkedList;
import java.util.List;

/**
 * @author XueguiYuan
 * @version 1.0 (created time: 2016/12/3).
 */
@NoArgsConstructor
@Getter
@Setter
@ToString(of = {"username", "email", "mobile"})
@Entity
@Table(name = "user")
public class User extends SecurityAbstractEntity {

    private String username;

    private String email;

    private String mobile;

    private String password;

    private String accessToken;

    @Override
    public String[] businessKeys() {
        return new String[]{"name"};
    }

    public static final Finder<Long, User> find = new Finder<>(User.class);

    /**
     * 撤销~级联撤销{@link Authorization }。
     * 因为参与者都已经被撤销，那么Authorization中只要有参与者就应该被撤销。
     */
    @Override
    public boolean delete() {
        for (Authorization authorization : Authorization.findByUser(this)) {
            authorization.delete();
        }
        return super.delete();
    }

    /**
     * 在某个范围下{@link Scope}为参与者{@link User}分配授权{@link Authority}。
     * 如果Authorization中已经存在Actor和Authority,就不需要授权，如果范围不为空，那么就更改范围。
     * 不存在就直接创建Authorization并保存。
     *
     * @param authority 可授权体
     * @param scope     范围
     */
    public void grant(Authority authority, Scope scope) {
        if (Authorization.exists(this, authority)) {
            if (scope != null) {
                Authorization authorization = Authorization.findByUserInAuthority(this, authority);
                authorization.changeScope(scope);
            }
            return;
        }
        new Authorization(this, authority, scope).save();
    }

    /**
     * 从参与者中撤销在某个范围下的授权。即撤销授权中心 {@link Authorization}。
     *
     * @param authority 授权 {@link Authority}
     * @param scope     范围 {@link Scope}
     */
    public void terminateAuthorityInScope(Authority authority, Scope scope) {
        Authorization authorization = Authorization.findByUserOfAuthorityInScope(this, authority, scope);
        authorization.delete();
    }

    /**
     * 为参与者分配授权。
     * 如果存在就直接返回，不存在就创建一个Authorization并保存。
     *
     * @param authority 授权 {@link Authority}
     */
    public void grant(Authority authority) {
        if (Authorization.exists(this, authority)) {
            return;
        }
        new Authorization(this, authority, null).save();
    }

    /**
     * 从参与者中撤销授权，即撤销授权中心 {@link Authorization}。
     *
     * @param authority 授权 {@link Authority}
     */
    public void terminate(Authority authority) {
        Authorization authorization = Authorization.findByUserInAuthority(this, authority);
        authorization.delete();
    }

    /**
     * 得到在某个范围下{@link Scope}参与者{@link User}的所有不重复的权限集合{@link Permission}
     *
     * @param scope 范围
     * @return 不重复的权限集合 {@link Permission}
     */
    public List<Permission> getPermissions(Scope scope) {
        List<Permission> results = new LinkedList<>();
        for (Authority authority : getAuthorities(scope)) {
            if (authority instanceof Permission) {
                results.add((Permission) authority);
            } else {
                Role role = (Role) authority;
                results.addAll(role.getPermissions());
            }
        }
        return results;
    }


    protected void checkName(String name) {
        Validate.notBlank(name, "name cannot be empty.");
    }


    /**
     * 根据范围获取到所有不重复的授权集合。
     *
     * @param scope 范围 {@link Scope}
     * @return 不重复的授权集合 {@link Authorization}
     */
    private List<Authority> getAuthorities(Scope scope) {
        return Authorization.findAuthoritiesByUserInScope(this, scope);
    }

}
